# Copyright (C) 2006  Apptility LLC  http://www.apptility.com
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

require 'application'
require 'test/unit'
require 'yaml'
require 'find'
require 'ftools'
require 'zlib'
#require 'mysql'
require 'fileutils'
require 'lib/odotcron'
require 's3-ruby'
require 'time'


class DbbackupController < ApplicationController

   protected
    def base_path
        File.dirname(__FILE__)
    end

    def permit_file?(path)
        true
        #@session['user'] and @session['user'].permit_file?(path)
    end

  public
   def backup
  
        to_root = '../' * File.dirname(__FILE__).count(File::SEPARATOR)

        @db_config = ActiveRecord::Base.configurations[RAILS_ENV]
  
        if(@db_config['adapter']=="mysql")
                      
          con = Mysql.new(@db_config['host'],@db_config['username'], @db_config['password'], @db_config['database'])
            @tables = con.query('show tables')
          con.close
          
          @keys = MashupNode.find(:all, :conditions => [ "name =? AND user_id =?", "amazonws", current_user.id])
            if(@keys.size==0)
              @access_key=''
              @secret_key=''
            else
              @keys.each do |@key_id|
                @access_key = @key_id.custom_field1
                @secret_key = AjubyTools.base64decode(@key_id.custom_field2)
              end 
            end 
           
        else
          render :action =>'backup'
        end
       
        @email=session[:user].email
  
        $conn = S3::AWSAuthConnection.new(@access_key, @secret_key)
        
        @bucketlist = $conn.list_all_my_buckets.entries.map { |bucket| bucket.name }
        
        @connectioncheck = ''
        @bucketlist.each do |@connectioncheck|
          @connectioncheck
        end
        if(@connectioncheck == '')
          @connectioncheck
        end
  
        #render :action =>'backup'
   end 
  
   def savebackup
               
        @savetype = params[:savetype]
        
        @savetypeamazon = params[:savetypeamazon]
       
        @db_config = ActiveRecord::Base.configurations[RAILS_ENV]
  
        datestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
        
        FileUtils.rm_rf("#{RAILS_ROOT}/db/backup")
              
        if(!File.exist?("#{RAILS_ROOT}/db/backup"))
          Dir.mkdir("#{RAILS_ROOT}/db/backup")
        end
   
        path="#{RAILS_ROOT}/db/backup"     

        $backup_folder =  File.join("#{path}",datestamp)
   
        if(!File.exist?("#{$backup_folder}"))
          Dir.mkdir("#{$backup_folder}")
        end
   
        if(@db_config['adapter']=="mysql")
          system("mysqldump -u #{@db_config['username']} -p#{@db_config['password']} -h #{@db_config['host']} #{@db_config['database']} > #{$backup_folder}/dbbackup.sql")
        else
          system("pg_dump -U #{@db_config['username']} -h #{@db_config['host']} #{@db_config['database']} > #{$backup_folder}/dbbackup.sql")
        end
   
        Zlib::GzipWriter.open("#{$backup_folder}/#{RAILS_ENV}_structure.sql.gz") do |gz|
          gz.write(File.read("#{$backup_folder}/dbbackup.sql"))
        end
  
        File.delete("#{$backup_folder}/dbbackup.sql")
        
        size = File.size("#{$backup_folder}/#{RAILS_ENV}_structure.sql.gz")
        
        $backupfile="#{$backup_folder}/#{RAILS_ENV}_structure.sql.gz"       
        
        filename = "#{RAILS_ENV}_structure.sql.gz"
        
        if(@savetype == 'bucket')
        
           if(@savetypeamazon == 'fetchbucket')
             
             @selectbucketname = params['selectbucketname'] 
                 
             base_name = File.basename($backupfile)

             data=File.open("#{$backup_folder}/#{RAILS_ENV}_structure.sql.gz", "r")

             response = $conn.put(@selectbucketname,"#{base_name}",S3::S3Object.new(data.read), { 'Content-Type' => 'application/x-gzip' }).http_response.message
                  #(data.read, {'blah' => 'foo'}),{ 'x-amz-acl' => 'public-read', 'Content-Type' => 'application/x-gzip' }).http_response.message
                        
               if(response == 'OK')
                 flash[:simplemsg] = "#{base_name} has been saved to your #{@selectbucketname} bucket."
                 redirect_back_or_default :action => 'backup'
               
               elsif(response == 'Bad Request')
                 flash[:message] = "Your proposed upload exceeds the maximum allowed object size."
                 redirect_back_or_default :action => 'backup'
                 
               elsif(response == 'Internal Server Error')
                 flash[:simplemsg] = "We encountered an internal error. Please try again."
                 redirect_back_or_default :action => 'backup'
                             
               else
                 flash[:message] = "There is a problem with your AWS account that prevents the operation from completing successfully. Please contact customer service at webservices@amazon.com."
                 redirect_back_or_default :action => 'backup'
               end
                       
                      
           elsif(@savetypeamazon == 'newbucket')
               
               @newbucketname = params[:bucket]
               
               base_name = File.basename($backupfile)
                              
               @newbucketresult = $conn.create_bucket(@newbucketname).http_response.message
                
                                    
               if(@newbucketresult == 'OK')
                  
                  data=File.open("#{$backup_folder}/#{RAILS_ENV}_structure.sql.gz", "r")

                  response = $conn.put(@newbucketname,"#{base_name}",S3::S3Object.new(data.read), { 'Content-Type' => 'application/x-gzip' }).http_response.message
                                              #(data.read, {'blah' => 'foo'}),{ 'x-amz-acl' => 'public-read', 'Content-Type' => 'application/x-gzip' }).http_response.message
                              
                     if(response == 'OK')
                        flash[:simplemsg] = "#{base_name} has been saved to your #{@newbucketname} bucket."
                        redirect_back_or_default :action => 'backup'
               
                     elsif(response == 'Bad Request')
                        flash[:message] = "Your proposed upload exceeds the maximum allowed object size."
                        redirect_back_or_default :action => 'backup'
                 
                     elsif(response == 'Internal Server Error')
                        flash[:message] = "We encountered an internal error during the saving of backup. Please try again."
                        redirect_back_or_default :action => 'backup'
                            
                     else
                        flash[:message] = "There is a problem with your AWS account that prevents the operation from completing successfully. Please contact customer service at webservices@amazon.com."
                        redirect_back_or_default :action => 'backup'
                     end         
                
               elsif(@newbucketresult == 'Conflict')
                  flash[:message] = "#{@newbucketname} is already present in your Account"
                  redirect_back_or_default :action => 'backup'
               
               elsif(@newbucketresult == 'Bad Request')
                  flash[:message] = "We encountered an error during the creation of bucket, following may be the reasons: <br/><br/>1. Bucket names may only contain the characters A-Z, a-z, 0-9, '_', '.', and '-'.<br/><br/>2. Bucket names must be at least 3 characters long, and at most 255 characters long.<br/><br/>3. You have attempted to create more buckets than allowed."
                  redirect_back_or_default :action => 'backup'
               
               elsif(@newbucketresult == 'Forbidden')
                  flash[:message] = "There is a problem with your AWS account that prevents the operation from completing successfully. Please contact customer service at webservices@amazon.com."
                  redirect_back_or_default :action => 'backup'
                              
               elsif(@newbucketresult == 'Internal Server Error')
                  flash[:message] = "We encountered an internal error during the creation of bucket. Please try again."
                  redirect_back_or_default :action => 'backup'
                  
               else
                  flash[:message] = "There is a problem with your AWS account that prevents the operation from completing successfully. Please contact customer service at webservices@amazon.com."
                  redirect_back_or_default :action => 'backup'
               end   

           else 
             flash[:message] = "Choose the correct option."
             redirect_back_or_default :action => 'backup'
           end
        
                      
        elsif (@savetype == 'server')
        
          
          datestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
          
          if(!File.exist?("#{RAILS_ROOT}/data/backup"))
            Dir.mkdir("#{RAILS_ROOT}/data/backup")
          end
   
          path="#{RAILS_ROOT}/data/backup"     

          server_backup_folder =  File.join("#{path}",datestamp)
   
          if(!File.exist?("#{server_backup_folder}"))
            Dir.mkdir("#{server_backup_folder}")
          end
                  
          data=File.open("#{$backup_folder}/#{RAILS_ENV}_structure.sql.gz", "r")
                  
          File.open("#{server_backup_folder}/#{RAILS_ENV}_structure.sql.gz","w+") {|f| f << data.read}
                  
          flash[:simplemsg] = "Backup saved to Server (#{server_backup_folder})"
                  
          redirect_back_or_default :action => 'backup'  
                   
        elsif (@savetype == 'download')
        
          path = "#{$backup_folder}/#{RAILS_ENV}_structure.sql.gz"
   
          if since = @request.env['HTTP_IF_MODIFIED_SINCE']
            begin
              require 'time'
              since = Time.httpdate(since) rescue Time.parse(since)
              return since < File.mtime(path)
              rescue Exception
            end
          end
       
          send_file path
                
                 
        else  
             
          @email=params[:email]
          @fname=session[:user].firstname
          @lname=session[:user].lastname
          
          if (@email == '')
            flash[:message] = "Email can't be blank"
            redirect_back_or_default :action => 'backup'
          else
          
       DbbackupDeliver.deliver_backupemail(@email,@fname,@lname,size,filename,$backupfile)
          flash[:simplemsg] = "Backup emailed to #{params[:email]}"
          redirect_back_or_default :action => 'backup'                  
          end
        end
   
   end
    
     
   def schedulebackup
   
    @node_name ="dbbackup"
    
    if !(@dbbackup_node = find_dbbackup_node(@node_name)).nil?
         update_dbbackup(@dbbackup_node, @params)
    end
    @dbbackup_node   
   
        $email=params[:email]
        $fname=session[:user].firstname
        $lname=session[:user].lastname
        @scheduletype = params[:scheduletype]
        
        Odotcron.create_backup_destroy_cron
        
        if (@scheduletype == 'never')
                  
                  #DbbackupDeliveryUtil.deliver_schedule
          flash[:simplemsg] = "Scheduled Backup Options (NEVER) Saved!"
          redirect_back_or_default :action => 'backup'
                  
        else
        
        if (@email == '')
          flash[:message] = "Email can't be blank"
          redirect_back_or_default :action => 'backup'
                  
        elsif(@scheduletype == 'hourly')
          Odotcron.create_backup_delivery_hourly_cron
          flash[:simplemsg] = "Scheduled Backup Options (HOURLY) Saved!"
          redirect_back_or_default :action => 'backup'
                  
        elsif(@scheduletype == 'daily')
          Odotcron.create_backup_delivery_daily_cron 
          flash[:simplemsg] = "Scheduled Backup Options (DAILY) Saved!"
          redirect_back_or_default :action => 'backup'       
                 
        else
          Odotcron.create_backup_delivery_weekly_cron
          flash[:simplemsg] = "Scheduled Backup Options (WEEKLY) Saved!"
          redirect_back_or_default :action => 'backup'
                
                  
        end  
        end  

   end
   
    private
     def find_dbbackup_node(node_name)
      
      @dbbackup_node = Dbbackup.find(:first, :conditions => [ "name =?", node_name])
      if @dbbackup_node == nil
        @dbbackup_node = Dbbackup.new 
      end  
      @dbbackup_node
    end
   
  
  def update_dbbackup (dbbackup, params)
      dbbackup.name = "dbbackup"
      dbbackup.firstname = session[:user].firstname
      dbbackup.lastname= session[:user].lastname
      dbbackup.email=params[:email]
      
      if dbbackup.save
        return true
      else
        return false
      end    
  end  
   
end  